<?php
/**
 * A base class to create generic html elements...
 * It does nothing itsef, it is a base class to other classes.
 * TODO COMMENT
 * TODO setTitle (set alt e title), setClass, setId,
 */
class Element
{
    public $style;
    public $tagName;

    /**
    * Creates a element... please dont use it directely...
    * @param $id        string the html id attribute
    * @param $class     the html class attribute
    * @param $label     the form label
    */
    public function element( $tagName, $id=NULL, $class=NULL, $label = NULL, $inner = NULL )
    {
        $this->tagName      = $tagName;
        $this->style        = new StyleClass();
        $this->id           = $id;
        //temporary to XHTML 1.1 Transitional
        $this->class        = $class;
        $this->label        = $label;
        $this->setInnerHTML( $inner );
    }

    /**
     * Add an value to a html attribute, if the attribute does not exist, set it.
     * It will always lowercase the attribute name.
     * If you wanna set case sensitive attribute please set $this->$attribute directely.
     *
     * @param string $attribute
     * @param string $value
     */
    public function addAttribute($attribute, $value)
    {
        $attribute = trim(strtolower($attribute)); //W3C recomends that all attributes are lowercase.

    	if ( $this->$attribute )
    	{
            $value = $this->$attribute.' '.$value;
    	}

    	$this->setAttribute($attribute, $value);

    }

    /**
     * Define a html attribute, do the same that addAttribute
     * It will always lowercase the attribute name.
     * If you wanna set case sensitive attribute please set $this->$attribute directely.
     *
     * @param string $attribute
     * @param string $value
     */
    public function setAttribute($attribute, $value)
    {
    	//TODO parse if you pass attribute with =
    	//TODO parse if attribute is array
    	$attribute = trim(strtolower($attribute)); //W3C recomends that all attributes are lowercase.

    	if ($attribute)
        {
            $this->$attribute = $value;
        }
    }

    /**
     * Return the content of an element.
     * It will always lowercase the attribute name.
     * If you wanna get case sensitive attribute please get $this->$attribute directely.
     *
     * @param string $attribute
     * @param string  $value
     * @return string
     */
    public function getAttribute($attribute=NULL)
    {
    	if ($attribute)
    	{
            $attribute = trim(strtolower($attribute)); //W3C recomends that all attributes are lowercase.
            return $this->$attribute;
    	}

    	return '';
    }

    //TODO public function getAttributeByValue

    /**
     * Remove/delete an attribute
     *
     * @param string $attribute
     */
    public function removeAttribute($attribute=NULL)
    {
    	if ($attribute)
    	{
            $attribute = trim(strtolower($attribute)); //W3C recomends that all attributes are lowercase.
            unset($this->$attribute);
    	}
    }

    //TODO public function removeAttributeByValue

    /**
     * Define an array of attributes.
     * Please user ['attributeName']=> 'attributeValue' in array.
     *
     * @param array $attributes
     */
    public function setAttributes($attributes=NULL)
    {
        if ( is_array($attributes) )
        {
            foreach ($attributes as $attribute => $value )
            {
                $this->addAttribute($attribute, $value);
            }
        }
    }

    /**
     * Return an array with all attributes
     *
     * @return array
     */
    public function getAttributes()
    {
        //TODO filter, test
        return get_object_vars($this);
    }

    /**
     * Return the style attribute in object.
     *      *
     * @return object
     */
    public function getStyle()
    {
        return $this->style;
    }

    public function setStyles($styles)
    {
        $this->style = $styles;
    }

    public function addStyle($style, $value=NULL)
    {
        if (is_array($style))
        {
            $this->setStyleArray($style);
        }
        else
        {
            $this->style->addStyle($style, $value);
        }
    }

    public function setStyleArray($array)
    {
        $this->style->setStyleClass($array);
    }

    public function addEvent($event, $value=NULL)
    {
    	if ($value)
    	{
            $this->addAttribute($event, $value.';');
    	}
    }

    public function getEvent($event)
    {
        return $this->getAttribute($event);
    }

    /**
    * Add one or array of inners.
    */
    public function addInner($inner)
    {
        if (is_array($inner))
        {
            foreach ( $inner as $line => $info )
            {
            	$this->addInner( $info );
            }
        }
        else
        {
        	//adds the id to index of array
            if ( is_object( $inner ) && $inner->id )
            {
                $this->inner[ $inner->id ] = $inner;
            }
            else
            {
            	$this->inner[] = $inner;
            }
        }
    }

    /**
    * Define inner
    *
    */
    public function setInnerHTML($inner)
    {
        $this->inner = $inner;
    }

    /**
    * Return the complete inner.
    *
    */
    public function getInnerHTML()
    {
        return $this->inner;
    }

    /**
    * Search in inner list, for an item that has the
    * attribute and value needed, returns only the first.
    * //TODO make it recursive
    */
    public function getInnerElement($elementId)
    {
        $inner = $this->getInnerHTML();

        if ( is_array( $inner) )
        {
            foreach ($inner as $line => $info)
            {
            	$line =$line;
                if ( $this->id == $elementId)
                {
                    return $info;
                }
            }
        }
        return null;
    }

    public function getElementById($id)
    {
    	return $this->getInnerElement($id);
    }

    /**
    * Remove specified
    *
    *
    */
    /*public function removeInnerElement($property, $value)
    {
        //TODO
        return null;
    }*/


    public function getElementStrings()
    {
    	$attributes = get_object_vars($this);

    	if (is_array($attributes))
    	{
            foreach ($attributes as $attribute => $value)
            {
                if ( $attribute != 'inner'  &&
                     $attribute != 'tagName' &&
                     $attribute != 'label'
                     )
                {

                    if ( is_array( $value ) )
                    {
                        $value = implode('',$value); //convert to string
                    }

                    $value = trim( $value.'') ; //force call __toString and remove unneed spaces

                    //only add the attribute if it has a value , value can be a object that has toString
                    if ( $value != null ) //important be diferent of null, only an if don't get 0 value
                    {
                        $result .= ''. $attribute.'="'.$value.'" ';
                    }
                }
            }

            $result = substr($result, 0,strlen($result)-1); //remove last space

            return $result;
    	}

    	return '';
    }

    /**
    * Render object to html
    *
    */
    public function __toString( $lineBreak = false )
    {
        $tagName        = $this->tagName;
        $elementStrings = $this->getElementStrings();

        if ( !$this->inner )
        {
            return "\n<$tagName $elementStrings />";
        }
        else
        {
            $lineBreak  = $lineBreak ? "\n" : '';

            $inner      = implode('', is_array( $this->inner ) ? $this->inner : array( $this->inner )); // transform it in array and implode by space, to concatenate all strings
            return "\n<$tagName {$elementStrings}>$lineBreak{$inner}</$tagName>";
        }
    }

    /**
    * Get all Field in a array of Array.
    */
    public function getArray()
    {
        $attributes  = $this->getPropertys()->getArray();
        //$events      = $this->getEvents()->getArray();
        $styles      = $this->getStyles()->getArray();
        $object      = $this->getObject();
        return array(
                        'object'    => $object,
                        'propertys' => $attributes,
                        //'events'    => $events,
                        'styles'    => $styles
                    );
    }

    public function getObject()
    {
        $object['class']        = get_class($this);
        $object['parentClass']  = get_parent_class($this);
        if (is_subclass_of($this,'Element') )
        {
            $object['Element']  = 'Element';
        }
        if (is_subclass_of($this,'ElementInner' ))
        {
            $object['ElementInner']  = 'ElementInner';
        }
        return $object;
    }


    /**
    * Define all the Field with 3 array, with attributes, events and styles
    * @param $attribute the attributes array, please see setArray of <code>propertys</code> class
    * @param $event     the events array, please see setArray of <code>events</code> class
    * @param $style     the styles array, please see setArray of <code>styles</code> class
    */
    public function setArray($attribute, $event, $style)
    {
    	//FIXME
    	$event = $event;
        $this->setAttributes($attribute);
        //$this->setEventArray($event);
        $this->setStyleArray($style);
    }

    //AUTO CSS FUNCTIONS

    /**
    * set the position of this element.
    *
    */
    public function setPosition($left=NULL, $top=NULL, $position = 'absolute')
    {
        $this->style->position = $position;
        $this->setTop( $top );
        $this->setLeft( $left );
    }

    public function setTop( $top )
    {
        $this->style->top   = $this->parseDimension( $top ) ;
    }

    public function setLeft( $left )
    {
    	$this->style->left  = $this->parseDimension( $left );
    }

    /**
    * Define the Dimensions of this element
    */
    public function setDimensions($width=NULL, $height=NULL, $position= 'absolute')
    {
        $this->style->position = $position;
        $this->setWidth( $width );
        $this->setHeight( $height );
    }

    /**
     * Set the height of element.
     * It will parse it as pixel if you do not pass it
     * It set the height property in style attribute
     *
     * @param $height the height in pixels or percent
     * @return void
     */
    public function setHeight( $height )
    {
        $this->style->height = $this->parseDimension( $height );
    }

    //TODO getHeight without px
    //TODO getWidth without px
    //TODO getTop without px
    //TODO getLeft without px


    /**
     * Set the width of element.
     * It will parse it as pixel if you do not pass it
     * It set the width property in style attribute
     *
     * @param $width the height in pixels or percent
     * @return void
     */
    public function setWidth( $width )
    {
    	$this->style->width = $this->parseDimension( $width );
    }

    /**
     * Used in setWidth and setHeight to detect if it need px in dimension
     *
     * @param $value
     * @return unknown_type
     */
    private function parseDimension( $value )
    {
        if ( strripos( $value, 'px') == 0 && strripos( $value, '%') == 0 )
        {
            $value  .= 'px';
        }

    	return $value;
    }

    /**
    * Define the bound of this element (setDimensions and SetPosition)
    */
    public function setBounds($left=NULL, $top=NULL, $width=NULL, $height=NULL, $position = 'absolute' )
    {
        $this->setPosition($left, $top, $position);
        $this->setDimensions($width, $height, $position);
    }

    /**
    * Define background Color
    *
    */
    public function setColor( $color, $background = null)
    {
        $this->style->color = $background;
        $this->setBackgroundColor( $background );
    }

    /**
    * Define background Color
    *
    */
    public function setBackgroundColor( $background )
    {
        $this->style->backgroundColor = $background;
    }

    /**
    * Define Border
    *
    */
    public function setBorder($width, $color, $style='solid')
    {
        $this->style->borderStyle = $style;
        $this->style->borderWidth = $width;
        $this->style->borderColor = $color;
    }

    /**
    * Define BackGround Image.
    *
    */
    public function setBackgroundImage($url, $repeat)
    {
        $this->style->backgroundImage  =  "url('$url')";
        $this->style->backgroundRepeat = $repeat;
    }

    public function setBorderCollapse( $collapse )
    {
        $this->style->borderCollapse = $collapse ? 'collapse' : null ;
    }
}
?>